﻿using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;
using Microsoft.DirectX;
using NGE;

namespace MH
{
    [Serializable]
    public struct DamageType
    {
        public const int Normal = 0;
        public const int Electric = 2;
        public const int Poison = 3;
        public const int Fire = 1;
        public const int Ice = -1;
    }
    [Serializable]
    public struct Datagram
    {
        [Serializable]
        public struct BattleMonsterInfo
        {
            public MonsterCode MonsterCode;
        }
        [Serializable]
        public struct PlayerCharacterSceneInfo
        {
            public string Name;
            public string InSceneName;
            public Vector3 Location;
            public Direction Direction;
        }
        [Serializable]
        public struct PlayerCharacterBattleInfo
        {
            //public string[] MonsterNames;
            public string Name;
            public int BattleTargetIndex;
            public int BattleAct;
        }
        [Serializable]
        public struct PlayerCharacterMoveInfo
        {
            public string Name;
            public Direction Direction;
            public float MoveSpeed;
            public int Steps;
        }
        [Serializable]
        public struct PlayerCharacterSayInfo
        {
            public string Name;
            public string Said;
        }
    }
    [Serializable]
    public struct CharacterActs
    {
        public const int TEST = 0x300;

        public const int Nothing = 0;

        public const int GETPC = 1;
        public const int GETScene = 2;
        public const int GETOPC = 3;

        public const int SETPC = 0x100;
        public const int SETScene = 0x101;
        public const int SETOPC = 0x102;

        public const int ChangeDirection = 0x200;
        public const int StartMove = 0x201;
        public const int StopMove = 0x202;
        public const int Say = 0x203;
        public const int EnterMetal = 0x204;
        public const int ExitMetal = 0x205;
        public const int EnterScene = 0x206;
        public const int ExitScene = 0x207;
        public const int EnterBattle = 0x208;
        public const int ExitBattle = 0x209;
        public const int BattleMoveCommanding = 0x221;
        public const int BattleAttackCommanding = 0x222;
        public const int BattleItemCommanding = 0x223;
        //public const int BattleFight = 0x211;
    }
    [Serializable]
    public class CharacterEventArgs : EventArgs
    {
        public CharacterEventArgs(int act, object arg)
        {
            Act = act;
            Arg = arg;
        }

        public int Act;
        public object Arg;

    }
    public delegate void CharacterEvent(object sender, CharacterEventArgs ea);
    public enum CharacterAvaterActs
    {
        Stand,
        Ready,
        Fight,
        Weapon,
        Item,
        Hit,
    }
    [Serializable]
    public class Spoil
    {
        public int Seed;
        public string Name;
    }
    [Serializable]
    public class Character : Sprite
    {
        public Character()
            : base()
        {
            inMetalIndex = -1;

            Scrpit = "";
            Type = SpriteType.NPC;
            DoorState = DoorState.Closed;
            DefaultDoorState = DoorState.Closed;
            Bag = new List<Prop>();

            Weapon = new Prop();
            Body = new Prop();
            Leg = new Prop();
            Foot = new Prop();
            Head = new Prop();
            Hand = new Prop();
        }

        #region for net
        [NonSerialized]
        public int Handle;

        [NonSerialized]
        public string Said = "";
        public int SaidDuration = 5;
        [NonSerialized]
        public double SaidStartTime;
        public Datagram.PlayerCharacterSceneInfo SceneInfo
        {
            get
            {
                Datagram.PlayerCharacterSceneInfo pcsi;
                pcsi.Direction = Direction;
                pcsi.Location = Location;
                pcsi.Name = Name;
                pcsi.InSceneName = InSceneName;
                return pcsi;
            }
            set
            {
                if (Name == value.Name)
                {
                    Direction = value.Direction;
                    Location = value.Location;
                    InSceneName = value.InSceneName;
                }
            }
        }
        //public Datagram.PlayerCharacterBattleInfo BattleInfo
        //{
        //    get
        //    {
        //        Datagram.PlayerCharacterBattleInfo pcbi;
        //        pcbi.Name = Name;
        //        //pcbi.BattleAct = BattleAct;
        //        pcbi.BattleAct = 0;
        //        pcbi.BattleTargetIndex = 0;
        //        return pcbi;
        //    }
        //    set
        //    {
        //        if (Name == value.Name)
        //        {
        //            BattleAct = value.BattleAct;
        //            BattleTargetIndex = value.BattleTargetIndex;
        //        }
        //    }
        //}
        public Datagram.PlayerCharacterSayInfo SayInfo
        {
            get
            {
                Datagram.PlayerCharacterSayInfo pcsay;
                pcsay.Name = Name;
                pcsay.Said = Said;
                return pcsay;
            }
            set
            {
                if (Name == value.Name)
                {
                    Said = value.Said;
                }
            }
        }
        #endregion


        public bool IsPalsy;
        public int G;//金币
        public string InSceneName;


        event CharacterEvent OnCharacterAct;        
        List<Metal> metals = new List<Metal>();

        public float MoveSpeed
        {
            get 
            {
                if (inMetalIndex < 0)
                {
                    return MoveSpeedPixel;
                }
                else
                {
                    return DrivingMetal.MoveSpeedPixel;
                }
            }
            set
            {
                MoveSpeedPixel = value;
            }
        }

        int inMetalIndex = -1;
        int searchMetal(string inSCName, Vector3 loc)
        {
            int i = 0;
            foreach (Metal mtl in metals)
            {
                if (mtl.Location == loc && mtl.InSceneName == inSCName)
                {
                    return i;
                }
                i++;
            }
            return -1;
        }



        public int InMetalIndex
        {
            get
            {
                return inMetalIndex;
            }
        }
        public int MetalCount
        {
            get
            {
                return metals.Count;
            }
        }
        public Metal DrivingMetal
        {
            get
            {
                if (inMetalIndex < 0)
                {
                    return null;
                }
                return metals[inMetalIndex];
            }
        }
        public void GotMetal(Metal mtl)
        {
            metals.Add(mtl);
        }
        void EnterMetal(int i)
        {
            if (NeedMove>0)
            {
                return;
            }
            inMetalIndex = i;
            metals[inMetalIndex].IsRunning = true;
            Location = metals[inMetalIndex].StopLocation;
            Direction = metals[inMetalIndex].StopDirection;
        }
        public void EnterMetal()
        {
            int i = searchMetal(InSceneName, Location);
            if (i > -1)
            {
                EnterMetal(i);
            }
        }
        public void ExitMetal()
        {
            if (NeedMove>0)
            {
                return;
            }
            if (inMetalIndex == -1)
            {
                return;
            }
            metals[inMetalIndex].StopDirection = Direction;
            metals[inMetalIndex].StopLocation = Location;
            metals[inMetalIndex].IsRunning = false;
            inMetalIndex = -1;
        }
        public Metal GetMetal(int i)
        {
            return metals[i];
        }
        

        public Vector3 GetNextLocationRight(Size tileSize)
        {
            Vector3 loc = GetNextLocation(tileSize);
            loc.X += tileSize.Width;
            return loc;
        }
        
        public void UnmontEventHandler()
        {
            OnCharacterAct = null;
        }
        public void MountEventHandler(CharacterEvent pce)
        {
            UnmontEventHandler();
            OnCharacterAct = new CharacterEvent(pce);
        }

        bool canMoveCHR(Scene scn, List<Character> chrs)
        {
            if (scn.TileCodeLayer[GetNextLocation(scn.TileSize)] != null)
            {
                if (!scn.TileCodeLayer[GetNextLocation(scn.TileSize)].CHR)
                {
                    return false;
                }
            }
            if (chrs != null)
            {
                foreach (Character npc in chrs)
                {
                    if (GetNextLocation(scn.TileSize).Equals(npc.Location))
                    {
                        if (npc.Type == SpriteType.Door)
                        {
                            if (npc.DoorState == DoorState.Locked)
                            {
                                return false;
                            }
                        }
                        else if (npc.HP > 0)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        bool canMoveMTL(Scene scn, List<Character> chrs)
        {
            if (scn.TileCodeLayer[GetNextLocation(scn.TileSize)] != null)
            {
                if (!scn.TileCodeLayer[GetNextLocation(scn.TileSize)].MTL)
                {
                    return false;
                }
            }
            if (chrs != null)
            {
                foreach (Character npc in chrs)
                {
                    if (GetNextLocation(scn.TileSize).Equals(npc.Location))
                    {
                        if (npc.Type == SpriteType.Door)
                        {
                            if (npc.DoorState == DoorState.Locked)
                            {
                                return false;
                            }
                        }
                        else if (npc.HP > 0)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        public bool CanMove(Scene scn, List<Character> chrs)
        {
            if (InMetalIndex < 0)
            {
                return canMoveCHR(scn, chrs);
            }
            else
            {
                return canMoveMTL(scn, chrs);
            }
        }

        public float Move(Direction dir, int steps, Scene scn, List<Character> chrs)
        {
            //if (IsFreezing)
            //{
            //    return 0;
            //}          
            if (needMovePixel > 0)
            {
                return 0;
            }

            Size tileSize = scn.TileSize;
            Direction = dir;
            if (OnCharacterAct != null)
            {
                Datagram.PlayerCharacterMoveInfo pcmi;
                pcmi.Name = Name;
                pcmi.MoveSpeed = 0;
                pcmi.Steps = 0;
                pcmi.Direction = Direction;
                OnCharacterAct(this, new CharacterEventArgs(CharacterActs.ChangeDirection, pcmi));
            }

            if (CanMove(scn, chrs) == false)
            {
                return 0;
            }

            needMoveStep = steps;
            if (Direction == Direction.U || Direction == Direction.D)
            {
                {
                    needMovePixel = tileSize.Height * needMoveStep;
                }
            }
            else if (Direction == Direction.L || Direction == Direction.R)
            {
                {
                    needMovePixel = tileSize.Width * needMoveStep;
                }
            }
            LastLocation = Location;

            float ms = MoveSpeed;

            if (OnCharacterAct != null)
            {
                Datagram.PlayerCharacterMoveInfo pcmi;
                pcmi.Name = Name;
                pcmi.MoveSpeed = ms;
                pcmi.Steps = steps;
                pcmi.Direction = Direction;
                OnCharacterAct(this, new CharacterEventArgs(CharacterActs.StartMove, pcmi));
            }
            return ms;
        }

        protected void Heartbeat()
        {
            if (Type == SpriteType.NPC)
            {
                if (IsAlwaysMoving)
                {
                    needMovePixel -= MoveSpeed;
                    return;
                }
            }

            if (needMovePixel > 0)
            {
                float ms = MoveSpeed;
                needMovePixel -= ms;
                if (Direction == Direction.U)
                {
                    Location.Y -= ms;
                }
                else if (Direction == Direction.L)
                {
                    Location.X -= ms;
                }
                else if (Direction == Direction.D)
                {
                    Location.Y += ms;
                }
                else if (Direction == Direction.R)
                {
                    Location.X += ms;
                }                
            }
        }
        public void Heartbeat(SceneComponent sceneCOM)
        {
            //if (IsFreezing)
            //{
            //    return;
            //}
            if (Type == SpriteType.Door)
            {
                if (sceneCOM.PC == null)
                {
                    return;
                }
                if (canOpenDoor(sceneCOM.CHRs, sceneCOM.SCN.TileSize))
                {
                    DoorState = DoorState.Open;
                }
                else
                {
                    RestoreDoorState();
                }
            }
            else if (Type == SpriteType.PC || Type == SpriteType.OPC || Type == SpriteType.NPC || Type == SpriteType.Monster)
            {
                bool check = false;
                if (needMovePixel > 0 && needMovePixel <= MoveSpeed)
                {
                    check = true;
                }
                Heartbeat();
                if (NeedMove == 0)
                {
                    if (cmdMoveQue == null)
                    {
                        cmdMoveQue = new Queue<Datagram.PlayerCharacterMoveInfo>();
                    }
                    if (cmdMoveQue.Count > 0)
                    {
                        Datagram.PlayerCharacterMoveInfo pcmi = cmdMoveQue.Dequeue();
                        float ms = Move(pcmi.Direction, pcmi.Steps, sceneCOM.SCN, sceneCOM.CHRs);
                        //if (Type == SpriteType.PC)
                        //{
                        //    sceneCOM.SCN.Move(pcmi.Direction, pcmi.Steps, ms);
                        //}
                    }
                }
                if (check)
                {
                    if (Type == SpriteType.PC)
                    {
                        if (OnCharacterAct != null)
                        {
                            OnCharacterAct(this, new CharacterEventArgs(CharacterActs.StopMove, SceneInfo));
                        }
                        EntryCode ec = sceneCOM.SCN.EntryCodeLayer[(int)Location.X,(int)Location.Y];
                        if (ec != null)
                        {
                            //IsFreezing = true;
                            Datagram.PlayerCharacterSceneInfo pcsi;
                            pcsi.Name = Name;
                            pcsi.InSceneName = ec.ToSceneFileName;
                            pcsi.Location = ec.DefaultLocation;
                            pcsi.Direction = ec.DefaultDirection;
                            CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.EnterScene, pcsi);
                            if (OnCharacterAct != null)
                            {
                                OnCharacterAct(this, pcea);
                            }
                        }
                        else
                        {
                            if (sceneCOM.SCN.MonsterCodeLayer != null)
                            {
                                MonsterCode mc = sceneCOM.SCN.MonsterCodeLayer[(int)Location.X, (int)Location.Y];
                                if (mc != null)
                                {
                                    Datagram.BattleMonsterInfo bmi;
                                    bmi.MonsterCode = mc;
                                    //for (int i = 0; i < mc.Count; i++)
                                    //{
                                    //    bmi.Names[i] = mc[i];

                                    //}
                                    CharacterEventArgs pcea = new CharacterEventArgs(CharacterActs.EnterBattle, bmi);
                                    if (OnCharacterAct != null)
                                    {
                                        OnCharacterAct(this, pcea);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        EntryCode ec = sceneCOM.SCN.EntryCodeLayer[(int)Location.X,(int)Location.Y];
                        if (ec != null)
                        {
                            InSceneName = ec.ToSceneName;
                        }
                    }
                }
                
            }
            if (IsAlwaysMoving)
            {
                if (Type == SpriteType.NPC || Type == SpriteType.Monster)
                {
                    if (needMovePixel <= 0)
                    {
                        if (Direction == Direction.L || Direction == Direction.R)
                        {
                            needMovePixel = sceneCOM.SCN.TileSize.Width;
                        }
                        else if (Direction == Direction.D || Direction == Direction.U)
                        {
                            needMovePixel = sceneCOM.SCN.TileSize.Height;
                        }
                    }
                }
            }
        }


        public void Talk(Scene scn, List<Character> chrs, ScriptComponent scriptCOM)
        {
            if (scn == null)
            {
                return;
            }
            Character npc = null;

            for (int i = 0; i < chrs.Count; i++)
            {
                if (chrs[i].Location == GetNextLocation(scn.TileSize))
                {
                    npc = chrs[i];
                }
            }
            if (npc == null)
            {
                if (!CanMove(scn, chrs))
                {
                    for (int i = 0; i < chrs.Count; i++)
                    {
                        if (chrs[i].Location == GetNextNextLocation(scn.TileSize))
                        {
                            npc = chrs[i];
                        }
                    }
                }
            }
            if (npc != null)
            {
                if (npc.Scrpit == null)
                {
                    return;
                }
                if (npc.Scrpit == string.Empty)
                {
                    return;
                }
                //freeze();

                npc.Direction = Util.GetOppositeDirection(Direction);
                scriptCOM.AS("clrctrl\n" + npc.Scrpit + "\n" + npc.Name + " rdir\nsetctrl");
            }
        }
        #region bag
        public List<Prop> Bag;

        public void BagIN(Prop obj)
        {
            if (obj.Name == null)
            {
                return;
            }
            else if (obj.Name == string.Empty)
            {
                return;
            }
            if (Bag == null)
            {
                Bag = new List<Prop>();
            }
            Bag.Add(obj);
            //Bag.Insert(0, obj);
        }
        
        public void BagOUT(int i)
        {
            if (i < 0)
            {
                return;
            }
            if (Bag == null)
            {
                Bag = new List<Prop>();
                return;
            }
            Bag.RemoveAt(i);
        }
        public void BagOUT(Guid guid)
        {
            int i = getPropIndex(guid);
            BagOUT(i);
        }

        public Prop BagUSE(int i)
        {
            if (Bag == null)
            {
                Bag = new List<Prop>();
                return null;
            }
            if (Bag.Count == 0)
            {
                return null;
            }
            return Bag[i];
        }
        public Prop BagUSE(Guid guid)
        {
            int i = getPropIndex(guid);
            if (i > -1)
            {
                return BagUSE(i);
            }
            return null;
        }

        int getPropIndex(Guid guid)
        {
            for (int i = 0; i < Bag.Count; i++)
            {
                if(Bag[i].GUID.Equals(guid))
                {
                    return i;
                }
            }
            return -1;
        }
        #endregion

        #region for slg
        public void AIBattle(Game game)
        {
            ScriptComponent scriptCOM = ((ScriptComponent)game.GetComponent("ScriptCOM"));
            SceneComponent sceneCOM = ((SceneComponent)game.GetComponent("SceneCOM"));
            Character tchr = sceneCOM.GetCHR(scriptCOM.GetValue("pc_name"));
            bool isInMtl;
            if (InMetalIndex < 0)
            {
                isInMtl = false;
            }
            else
            {
                isInMtl = true;
            }
            if (IsInCanSeeZone(7, 7, sceneCOM.SCN, tchr.Location) == false)
            {
                //if (!IsSleeping)
                {
                    scriptCOM.AS(Name + " isfocus");
                    //scriptCOM.AS("music loop data\\sound\\" + sceneCOM.SCN.MusicFileName);
                    string script = AIWalk(Location, tchr.Location, sceneCOM.SCN, isInMtl);
                    scriptCOM.AS(script);
                    scriptCOM.AS("block " + Name + " nothing");
                }
            }
            else
            {
                //IsSleeping = false;
                scriptCOM.AS("music loop data\\sound\\106.nsnd");
                bool canatk = false;
                string script = AIMove(out canatk, Location, tchr.Location, sceneCOM.SCN, sceneCOM.CHRs, isInMtl);
                scriptCOM.AS(script);
                scriptCOM.AS("block " + Name + " nothing");
                if (canatk)
                {
                    scriptCOM.AS(Name + " attack " + tchr.Name);
                }
            }
            //if (!IsSleeping)
            {
                scriptCOM.AS("delay 600");
            }
            scriptCOM.AS("battle notbusy");
        }
        string AIWalk(Vector3 from, Vector3 to, Scene scn, bool isInMtl)
        {
            int timeout = 0;
            string script = "";
            Vector3 nowloc = from;

            int mr = Util.Roll(0, MoveRangeMax);

            for (int i = 0; i < mr; i++)
            {
                bool repet;
                int d;
                Direction dir;
                timeout = 0;

                do
                {
                    timeout++;
                    d = Util.Roll(0, 3);
                    dir = (Direction)d;

                    Vector3 nextloc = GetNextLocation(nowloc, dir, scn.TileSize);
                    if (scn.EntryCodeLayer[(int)nextloc.X,(int)nextloc.Y] == null)
                    {
                        if (scn.CanReach(nextloc, isInMtl))
                        {
                            repet = false;
                        }
                        else
                        {
                            repet = true;
                        }
                    }
                    else
                    {
                        repet = true;
                    }
                } while (repet && timeout < 4);//find direction
                if (timeout < 4)
                {
                    script += Name + " move " + dir.ToString().ToLower() + " 1\n";
                }
            }
            return script;
        }
        #region important AI
        bool canReach(Vector3 loc, Scene scn, List<Character> chrs)
        {
            if (scn.TileCodeLayer[loc] != null)
            {
                if (!scn.TileCodeLayer[loc].CHR)
                {
                    return false;
                }
            }
            foreach (Character spr in chrs)
            {
                if (spr.Name != Name)
                {
                    if (loc.Equals(spr.Location))
                    {
                        if (spr.Type == SpriteType.Door)
                        {
                            if (spr.DoorState == DoorState.Locked)
                            {
                                return false;
                            }
                        }
                        else if (spr.HP > 0)
                        {
                            return false;
                        }
                    }
                }
            }
            return true;
        }
        List<Vector3> getCanReachLocations(Vector3 loc, Scene scn, List<Character> chrs)
        {
            List<Vector3> targetLoc = new List<Vector3>();

            Vector3 locU = loc;
            locU.Y -= scn.TileSize.Height;

            Vector3 locL = loc;
            locL.X -= scn.TileSize.Width;

            Vector3 locD = loc;
            locD.Y += scn.TileSize.Height;

            Vector3 locR = loc;
            locR.X += scn.TileSize.Width;

            targetLoc.Add(locU);
            targetLoc.Add(locL);
            targetLoc.Add(locD);
            targetLoc.Add(locR);

            for (int i = 3; i > -1; i--)
            {
                if (canReach(targetLoc[i], scn, chrs) == false)
                {
                    targetLoc.RemoveAt(i);
                }
            }

            return targetLoc;
        }
        List<Vector3> getCanAttackLocations(int minAttackRange, int maxAttackRange, Vector3 loc, Scene scn, List<Character> chrs)
        {
            List<Vector3> targetLoc = new List<Vector3>();

            for (int i = minAttackRange; i <= maxAttackRange; i++)
            {
                Vector3 locU = loc;
                locU.Y -= scn.TileSize.Height * i;

                Vector3 locL = loc;
                locL.X -= scn.TileSize.Width * i;

                Vector3 locD = loc;
                locD.Y += scn.TileSize.Height * i;

                Vector3 locR = loc;
                locR.X += scn.TileSize.Width * i;

                targetLoc.Add(locU);
                targetLoc.Add(locL);
                targetLoc.Add(locD);
                targetLoc.Add(locR);
            }

            for (int i = 3; i > -1; i--)
            {
                if (canReach(targetLoc[i], scn, chrs) == false)
                {
                    targetLoc.RemoveAt(i);
                }
            }

            return targetLoc;
        }
        Vector3 getLocationNearestTargetLocation(List<Vector3> from_these_loc, Vector3 tarLoc)
        {
            int which = 0;
            float d = float.MaxValue;
            for (int i = 0; i < from_these_loc.Count; i++)
            {
                float t = Util.GetDistance(tarLoc, from_these_loc[i]);
                if (t < d)
                {
                    d = t;
                    which = i;
                }
            }
            return from_these_loc[which];
        }
        #endregion
        string AIMove(out bool canAttack, Vector3 from, Vector3 to, Scene scn, List<Character> chrs, bool isInMtl)
        {
            canAttack = false;
            List<string> strs = new List<string>();

            List<Vector3> canAttackLocs = getCanAttackLocations(AttackRangeMin, AttackRangeMax, to, scn, chrs);
            Vector3 nearestAttackLoc = getLocationNearestTargetLocation(canAttackLocs, from);

            Vector3 LocationCopy = from;

            for (int i = 0; i < MoveRangeMax; i++)
            {
                if (LocationCopy.Equals(nearestAttackLoc))
                {
                    canAttack = true;
                    //Direction dir = Util.GetDirection(LocationCopy, to);
                    //strs.Add(Name + " dir " + dir.ToString());
                    break;
                }
                List<Vector3> canReachLocs = getCanReachLocations(LocationCopy, scn, chrs);
                Vector3 thisStepLoc = getLocationNearestTargetLocation(canReachLocs, nearestAttackLoc);
                if (thisStepLoc.Y < LocationCopy.Y)
                {
                    //move up
                    LocationCopy.Y -= scn.TileSize.Height;
                    strs.Add(Name + " move u");
                }
                else if (thisStepLoc.X < LocationCopy.X)
                {
                    //move left
                    LocationCopy.X -= scn.TileSize.Width;
                    strs.Add(Name + " move l");
                }
                else if (thisStepLoc.Y > LocationCopy.Y)
                {
                    //move down
                    LocationCopy.Y += scn.TileSize.Height;
                    strs.Add(Name + " move d");
                }
                else if (thisStepLoc.X > LocationCopy.X)
                {
                    //move right
                    LocationCopy.X += scn.TileSize.Width;
                    strs.Add(Name + " move r");
                }
                if (LocationCopy.Equals(nearestAttackLoc))
                {
                    canAttack = true;
                    //Direction dir = Util.GetDirection(LocationCopy, to);
                    //strs.Add(Name + " dir " + dir.ToString());
                    break;
                }
            }

            string cmd = "";
            foreach (string str in strs)
            {
                cmd += str + "\n";
            }
            return cmd;
        }
        bool AIAttack(Vector3 from, Vector3 to, Scene scn, bool isInMtl)
        {
            //AttackRangeMin = 2;
            //AttackRangeMax = 3;

            if (from.Y == to.Y)
            {
                float dis = to.X - from.X;
                dis = Math.Abs(dis);
                dis /= scn.TileSize.Width;
                if (dis >= AttackRangeMin && dis <= AttackRangeMax)
                {
                    // can attack
                    //cmd = "effect data\\sound\\131.nsnd";
                    return true;
                }
            }
            else if (from.X == to.X)
            {
                float dis = to.Y - from.Y;
                dis = Math.Abs(dis);
                dis /= scn.TileSize.Height;
                if (dis >= AttackRangeMin && dis <= AttackRangeMax)
                {
                    //cmd = "effect data\\sound\\131.nsnd";
                    return true;
                }
            }
            return false;
        }
        public int MonsterAttackRangeMin;
        public int MonsterAttackRangeMax;
        public int MonsterMoveRangeMax;


        public List<Vector3> GetCanMoveZone(Scene scn)
        {
            List<Vector3> tmp = Util.GetZone(MoveRangeMax);
            List<Vector3> tmp2 = new List<Vector3>();
            for (int i = 0; i < tmp.Count; i++)
            {
                Vector3 offset = tmp[i];
                offset.X *= scn.TileSize.Width;
                offset.Y *= scn.TileSize.Height;
                if (scn.CanReach(this, offset))
                {
                    tmp2.Add(offset);
                }
            }
            return tmp2;
        }
        public bool IsInCanMoveZone(Vector3 loc, Scene scn)
        {
            foreach (Vector3 v3 in GetCanMoveZone(scn))
            {
                if (Util.Vector3AddVector3(v3, Location).Equals(loc))
                {
                    return true;
                }
            }
            return false;
        }
        public List<Vector3> GetCanAttackZone(Scene scn)
        {
            List<Vector3> tmp = new List<Vector3>();
            for (int d = 0; d < 4; d++)
            {
                Direction dir = (Direction)d;
                for (int i = AttackRangeMin; i <= AttackRangeMax; i++)
                {
                    Vector3 loc = new Vector3();
                    if (dir == Direction.U)
                    {
                        loc.Y -= scn.TileSize.Height * i;
                    }
                    else if (dir == Direction.L)
                    {
                        loc.X -= scn.TileSize.Width * i;
                    }
                    else if (dir == Direction.D)
                    {
                        loc.Y += scn.TileSize.Height * i;
                    }
                    else if (dir == Direction.R)
                    {
                        loc.X += scn.TileSize.Width * i;
                    }
                    tmp.Add(loc);
                }
            }
            return tmp;

        }
        public bool IsInCanAttackZone(Vector3 loc, Scene scn)
        {
            foreach (Vector3 v3 in GetCanAttackZone(scn))
            {
                if (Util.Vector3AddVector3(v3, Location).Equals(loc))
                {
                    return true;
                }
            }
            return false;
        }

        public int MoveRangeMax
        {
            get
            {
                if (Type == SpriteType.Monster)
                {
                    return MonsterMoveRangeMax + 3;
                }
                return Foot.RangeMax + 3;
            }
        }
        public int AttackRangeMin
        {
            get
            {
                if (Type == SpriteType.Monster)
                {
                    return MonsterAttackRangeMin + 1;
                }
                return Weapon.RangeMin + 1;
            }
        }
        public int AttackRangeMax
        {
            get
            {
                if (Type == SpriteType.Monster)
                {
                    return MonsterAttackRangeMax + 1;
                }
                return Weapon.RangeMax + 1;
            }
        }

        public List<Vector3> GetCanFindZone(Direction dir, int range, int wide, Scene scn)
        {
            Vector3 myloc = Location;
            List<Vector3> tmp = new List<Vector3>();
            bool isinMetal = false;
            if (InMetalIndex > -1)
            {
                isinMetal = true;
            }

            int s = wide / 2;
            if (dir == Direction.U)
            {
                for (int k = -s; k <= s; k++)
                {
                    Vector3 loc = myloc;

                    loc.X += k * scn.TileSize.Width;

                    for (int i = 1; i <= range; i++)
                    {
                        loc.Y -= scn.TileSize.Height;

                        if (scn.CanReach(loc, isinMetal))
                        {
                            tmp.Add(loc);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            else if (dir == Direction.D)
            {
                for (int k = -s; k <= s; k++)
                {
                    Vector3 loc = myloc;

                    loc.X += k * scn.TileSize.Width;

                    for (int i = 1; i <= range; i++)
                    {
                        loc.Y += scn.TileSize.Height;

                        if (scn.CanReach(loc, isinMetal))
                        {
                            tmp.Add(loc);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            else if (dir == Direction.L)
            {
                for (int k = -s; k <= s; k++)
                {
                    Vector3 loc = myloc;

                    loc.Y += k * scn.TileSize.Width;

                    for (int i = 1; i <= range; i++)
                    {
                        loc.X -= scn.TileSize.Height;

                        if (scn.CanReach(loc, isinMetal))
                        {
                            tmp.Add(loc);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            else if (dir == Direction.R)
            {
                for (int k = -s; k <= s; k++)
                {
                    Vector3 loc = myloc;

                    loc.Y += k * scn.TileSize.Width;

                    for (int i = 1; i <= range; i++)
                    {
                        loc.X += scn.TileSize.Height;

                        if (scn.CanReach(loc, isinMetal))
                        {
                            tmp.Add(loc);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            return tmp;
        }

        public bool IsInCanSeeZone(int range, int wide, Scene scn, Vector3 to)
        {
            List<Vector3> tmp = new List<Vector3>();
            tmp = GetCanFindZone(Direction.U, range, wide, scn);
            foreach (Vector3 loc in tmp)
            {
                if (loc.Equals(to))
                {
                    return true;
                }
            }
            tmp = GetCanFindZone(Direction.D, range, wide, scn);
            foreach (Vector3 loc in tmp)
            {
                if (loc.Equals(to))
                {
                    return true;
                }
            }
            tmp = GetCanFindZone(Direction.L, range, wide, scn);
            foreach (Vector3 loc in tmp)
            {
                if (loc.Equals(to))
                {
                    return true;
                }
            }
            tmp = GetCanFindZone(Direction.R, range, wide, scn);
            foreach (Vector3 loc in tmp)
            {
                if (loc.Equals(to))
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsSaw(Scene scn, Vector3 chr_loc)
        {
            return IsInCanSeeZone(7, 7, scn, chr_loc);
        }

        #endregion

        #region for fight
        public int LVL;
        public int EXP;
        public int HP;
        public int HPMax;
        public int AP;

        public bool IsDead
        {
            get
            {
                if (HP <= 0)
                {
                    return true;
                }
                return false;
            }
        }
        public bool IsNothing
        {
            get
            {
                if (NeedMove > 0)
                {
                    return false;
                }
                if (AvatarAct != CharacterAvaterActs.Stand)
                {
                    return false;
                }
                return true;
            }
        }

        public Prop Weapon;
        public Prop Body;
        public Prop Leg;
        public Prop Foot;
        public Prop Head;
        public Prop Hand;

        public void Use(int i)
        {
            Prop prop = Bag[i];
            if (prop.Type == PropType.Supply)
            {
                BagOUT(i);
            }
            else if (prop.Type == PropType.Tool)
            {
            }
            else if (prop.Type == PropType.Weapon)
            {
                Weapon = prop;
                BagOUT(i);
            }
            else if (prop.Type == PropType.Body)
            {
                Body = prop;
                BagOUT(i);
            }
            else if (prop.Type == PropType.Leg)
            {
                Leg = prop;
                BagOUT(i);
            }
            else if (prop.Type == PropType.Foot)
            {
                Foot = prop;
                BagOUT(i);
            }
            else if (prop.Type == PropType.Head)
            {
                Head = prop;
                BagOUT(i);
            }
            else if (prop.Type == PropType.Hand)
            {
                Hand = prop;
                BagOUT(i);
            }
        }
        public void Drop(int i)
        {
            BagOUT(i);
        }
        public void Unequip(int pt)
        {
            Prop prop;
            if (pt == PropType.Weapon)
            {
                prop = Weapon;
                BagIN(prop);
                Weapon = new Prop();
            }
            else if (pt == PropType.Body)
            {
                prop = Body;
                BagIN(prop);
                Body = new Prop();
            }
            else if (pt == PropType.Leg)
            {
                prop = Leg;
                BagIN(prop);
                Leg = new Prop();
            }
            else if (pt == PropType.Foot)
            {
                prop = Foot;
                BagIN(prop);
                Foot = new Prop();
            }
            else if (pt == PropType.Head)
            {
                prop = Head;
                BagIN(prop);
                Head = new Prop();
            }
            else if (pt == PropType.Hand)
            {
                prop = Hand;
                BagIN(prop);
                Hand = new Prop();
            }
        }

        public int APSpeed
        {
            get
            {
                return 10;
            }
        }
        public double Damage
        {
            get
            {
                return Weapon.Damage + MonsterDamage;
            }
        }
        public double Defense
        {
            get
            {
                return Body.Defense + Leg.Defense + Foot.Defense + Head.Defense + Hand.Defense + MonsterDefense;
            }
        }
        public double Accurate
        {
            get
            {
                return Weapon.Accurate + MonsterAccurate;
            }
        }
        public double Missrate
        {
            get
            {
                return Body.Missrate + Leg.Missrate + Foot.Missrate + Head.Missrate + Hand.Missrate + MonsterMissrate;
            }
        }
        public double Armor
        {
            get
            {
                return Body.Armor + Leg.Armor + Foot.Armor + Head.Armor + Hand.Armor + MonsterArmor;
            }
        }
        
        protected Queue<Datagram.PlayerCharacterMoveInfo> cmdMoveQue;
        protected void cmdMoveEnqueue(Datagram.PlayerCharacterMoveInfo cmi)
        {
            if (cmdMoveQue == null)
            {
                cmdMoveQue = new Queue<Datagram.PlayerCharacterMoveInfo>();
            }
            cmdMoveQue.Enqueue(cmi);
        }

        public void Move(Datagram.PlayerCharacterMoveInfo cmi)
        {
            cmdMoveEnqueue(cmi);
        }
        public void ClearCommandQueue()
        {
            if (cmdMoveQue == null)
            {
                return;
            }
            cmdMoveQue.Clear();
        }

       
        [NonSerialized]
        public CharacterAvaterActs AvatarAct; 
        public CharacterAvaterActs LastAvatarAct;
        [NonSerialized]
        public bool AvatarFlip;

        public NAnimation AvatarReady;
        public NAnimation AvatarFight;
        public NAnimation AvatarWeapon;
        public NAnimation AvatarItem;
        public NAnimation AvatarHit;

        //public int BattleAct;
        //public int BattleTargetIndex;

        #endregion

        #region for npc

        public List<Spoil> Spoils = new List<Spoil>();

        public string Scrpit;
        public Vector3 DefaultLocation;
        public Direction DefaultDirection;
        public DoorState DefaultDoorState;
        public bool IsEnemy;
        public bool IsAlwaysMoving;
        public bool IsSleeping;

        public DoorState DoorState;
        public BoxState BoxState;

        public bool IsInDoorZone(Microsoft.DirectX.Vector3 loc, System.Drawing.Size tileSize)
        {
            loc.X /= tileSize.Width;
            loc.Y /= tileSize.Height;


            Vector3 lloc = Location;
            lloc.X /= tileSize.Width;
            lloc.Y /= tileSize.Height;
            if (loc.Equals(lloc))
            {
                return true;
            }
            if (loc.X == lloc.X)
            {
                if (loc.Y == lloc.Y - (AvatarSize.Height / tileSize.Height - 1) * tileSize.Height)
                {
                    return true;
                }
            }
            return false;
        }

        public void RestoreDoorState()
        {
            DoorState = DefaultDoorState;
        }
        public void RestoreDirection()
        {
            Direction = DefaultDirection;
        }

        bool canOpenDoor(List<Character> chrs, System.Drawing.Size tileSize)
        {
            foreach (Character pc in chrs)
            {
                if (canOpenDoor(pc, tileSize))
                {
                    return true;
                }
            }
            return false;
        }
        bool canOpenDoor(Character chr, System.Drawing.Size tileSize)
        {
            if (chr.Type == SpriteType.Door)
            {
                return false;
            }
            if (chr.NeedMove > 0 && IsInDoorZone(chr.GetNextLocation(tileSize), tileSize))
            {
                return true;
            }
            else if (IsInDoorZone(chr.Location, tileSize))
            {
                return true;
            }
            else if (chr.NeedMove > 0 && chr.Direction == Direction.D && IsInDoorZone(chr.LastLocation, tileSize))
            {
                return true;
            }
            return false;
        }

        #endregion

        #region for monster

        public double MonsterDamage;
        public double MonsterDefense;
        public double MonsterArmor;
        public double MonsterAccurate;
        public double MonsterMissrate;

        public double MonsterDamageA;
        public double MonsterDamageB;
        public double MonsterDamageC;
        public double MonsterDamageD;
        
        public int MonsterDamageAType = 0;
        public int MonsterDamageBType = 0;
        public int MonsterDamageCType = 0;
        public int MonsterDamageDType = 0;
        
        public NAnimation MonsterAttackA1;
        public NAnimation MonsterAttackA2;
        public NAnimation MonsterAttackA3;
        public Vector3 MonsterAttackA1Offset;

        public NAnimation MonsterAttackB1;
        public NAnimation MonsterAttackB2;
        public NAnimation MonsterAttackB3;
        public Vector3 MonsterAttackB1Offset;

        public NAnimation MonsterAttackC1;
        public NAnimation MonsterAttackC2;
        public NAnimation MonsterAttackC3;
        public Vector3 MonsterAttackC1Offset;

        public NAnimation MonsterAttackD1;
        public NAnimation MonsterAttackD2;
        public NAnimation MonsterAttackD3;
        public Vector3 MonsterAttackD1Offset;

        #endregion
    }
}
